package middleware

import (
	"AppBigDevops/src/common"
	"AppBigDevops/src/config"
	"AppBigDevops/src/models"
	"fmt"
	"github.com/gin-gonic/gin"
	"go.uber.org/zap"
	"strings"
	"time"
)

func JWTAuthMiddleware() func(c *gin.Context) {

	return func(c *gin.Context) {

		// 01 去header里面 找 Authorization 如果没有 直接报 401
		// 02 如果有 拿到token 长字符串 jwt 解析
		// 03 验证 token又没有过期
		// 04 将claim对象 传递下去，给业务处理函数使用
		// 05 续期

		authHeader := c.Request.Header.Get("Authorization")
		if authHeader == "" {

			common.Req401WithWithDetailed(gin.H{"reload": true}, "未登录或非法访问没有Authorization的header", c)
			c.Abort()
			return
		}
		parts := strings.SplitN(authHeader, " ", 2)

		// authHeaderString格式校验： Bearer wdkkwdk12312k3dj32ijed2j897fdhwuenf3n4iuryysuhsdjnbfdkjsad
		if !(len(parts) == 2 && parts[0] == "Bearer") {
			common.Req401WithWithDetailed(gin.H{"reload": true}, "请求头中的auth格式错误", c)

			//阻止调用后续的函数
			c.Abort()
			return
		}

		sc := c.MustGet(common.GIN_CTX_CONFIG_CONFIG).(*config.ServerConfig)

		userClaims, err := models.ParseToken(parts[1], sc)
		if err != nil {
			common.Req401WithWithDetailed(gin.H{"reload": true}, fmt.Sprintf("parseToken 解析token包含的信息错误:%v", err.Error()), c)

			c.Abort()
			return
		}

		// 续期的逻辑 还没写
		// 判断token是否快过期 ，定义1个临期窗口
		// 重新生成一个token ，需要前端配合 下次请求的时候带上新的token

		// 假设 过期时间 10:00:00
		// 假设 当前时间 09:59:01
		// 假设 缓冲时间段 1分钟
		// 结果 59 < 60

		if userClaims.RegisteredClaims.ExpiresAt.Unix()-time.Now().Unix() < int64(sc.JWTC.BufferDuration/time.Second) {
			sc.Logger.Info("jwt临期了,刷新jwt",
				zap.String("user", userClaims.Username),
				zap.Any("老token过期时间", userClaims.RegisteredClaims.ExpiresAt),
				zap.Any("临期窗口", sc.JWTC.BufferDuration),
			)

			// 重新生成一个新token
			newToken, err := models.GenJwtToken(userClaims.User, sc)
			if err != nil {
				common.Result5XX(0, gin.H{}, fmt.Sprintf("parseToken 解析token包含的信息错误:%v", err.Error()), c)
				//阻止调用后续的函数
				c.Abort()
			}

			// 设置到header中
			c.Header("new-token", newToken)
		}

		//将当前请求的username信息保存到请求的上下文c上
		//后续的处理函数可以通过c.Get("username")来获取请求的用户信息
		c.Set(common.GIN_CTX_JWT_CLAIM, userClaims)
		c.Next()

	}
}
